package com.maxdu.labs.stt.fragments;

import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;

import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.example.stt.R;
import com.facebook.Request;
import com.facebook.Request.GraphUserListCallback;
import com.facebook.Response;
import com.facebook.Session;
import com.facebook.SessionState;
import com.facebook.UiLifecycleHelper;
import com.facebook.model.GraphUser;
import com.facebook.widget.ProfilePictureView;
import com.maxdu.labs.stt.constants.Constants;
import com.maxdu.labs.stt.constants.FriendRequestConstants;
import com.maxdu.labs.stt.models.db.FriendRequestDBHelper;
import com.parse.FindCallback;
import com.parse.ParseException;
import com.parse.ParseObject;
import com.parse.ParseQuery;
import com.parse.SaveCallback;

public class FriendsFragment extends Fragment {

	private final static String FIND_REQUESTS_PENDING = "find_requests_pending";
	private final static String FIND_REQUESTS_ACCEPTED = "find_requests_accepted";
	
	private TextView noFriendTView;
	private ListView myFriendsListV;
	private ListView myFriendsToInviteLV;
	private List<ParseObject> myAcceptedFriends;
	private List<ParseObject> myPendingFriends;
	private List<GraphUser> allMyFBFriends;
	private List<String> myAcceptedFriendsStr;
	private List<String> myPendingFriendsStr;
	
	private List <GraphUser> myFriendsCouldInvite;
	
	private ProfilePictureView profilePictureView;
	private TextView userNameView;
	
	private String currentUserId;
	private ProgressBar loading;
	
	private MyFriendsAdapter adapter;
	private MyFriendsToInviteAdapter adapter2;
	
	private final TaskResultObservable taskOb = new TaskResultObservable();
	
	private UiLifecycleHelper uiHelper;
	private Session.StatusCallback callback = new Session.StatusCallback() {
	    @Override
	    public void call(final Session session, final SessionState state, final Exception exception) {
	        onSessionStateChange(session, state, exception);
	    }
	};
	
	Boolean hasAppFriends = null;
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
	}

	@Override
	public View onCreateView(LayoutInflater inflater,
			@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
		super.onCreateView(inflater, container, savedInstanceState);
		
		View view = inflater.inflate(R.layout.frag_friends, container, false);
		
		profilePictureView = (ProfilePictureView) view.findViewById(R.id.selection_profile_pic);
	    profilePictureView.setCropped(true);
	    
	    noFriendTView = (TextView) view.findViewById(R.id.no_friend_request_to_display);
	    noFriendTView.setVisibility(View.GONE);
	    
	    userNameView = (TextView) view.findViewById(R.id.selection_user_name);
	    myFriendsListV = (ListView) view.findViewById(R.id.list_friends);
	    myFriendsToInviteLV = (ListView) view.findViewById(R.id.list_friends_to_invite);
	    Button inviteFriendsBtn = (Button) view.findViewById(R.id.btn_invite_friends);
	    
	    
	    loading = (ProgressBar)view.findViewById(R.id.progressBar1);
	    loading.setVisibility(View.GONE);
	    
	    uiHelper = new UiLifecycleHelper(getActivity(), callback);
	    uiHelper.onCreate(savedInstanceState);
        
        myAcceptedFriends = new ArrayList<ParseObject>();
        myPendingFriends = new ArrayList<ParseObject>();
        myFriendsCouldInvite = new ArrayList<GraphUser>();
        myAcceptedFriendsStr = new ArrayList<String>();
        myPendingFriendsStr = new ArrayList<String>();
       
       
        adapter = new MyFriendsAdapter(getActivity(), R.layout.row_my_friend, myAcceptedFriends);
		myFriendsListV.setAdapter(adapter);
		
		adapter2 = new MyFriendsToInviteAdapter(getActivity(), R.layout.row_my_friend, myFriendsCouldInvite);
		myFriendsToInviteLV.setAdapter(adapter2);
		
		Session.openActiveSession(getActivity(), true, new Session.StatusCallback() {
		    @Override
		    public void call(Session session, SessionState state, Exception exception) {
		        if(session.isOpened()) {
		            Log.w(Constants.LOG_TAG, "FB session opened successfully");
		            makeMeRequest(session);
		        } else {
		        	if(exception != null){
		        		Log.w(Constants.LOG_TAG, "FB session not opened ... " + exception.toString());
		        	}
		        }
		    }
		});
		
		inviteFriendsBtn.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View arg0) {
				
				loading.setVisibility(View.VISIBLE);
				noFriendTView.setVisibility(View.GONE);
				myFriendsListV.setVisibility(View.GONE);
				myFriendsToInviteLV.setVisibility(View.VISIBLE);
				
	    		ResultObserver resultOb = new ResultObserver(taskOb);
	    		taskOb.addObserver(resultOb);
	    		
				//get the STT friends list
				if(currentUserId != null){
					if (hasAppFriends != null){
						//get FB Friends
						getFBFriends();
						
						//get Pending request
	            	    GetFriendsTask task = new GetFriendsTask();
	            	    String[] params = new String[2];
	            	    params[0] = currentUserId;
	            	    params[1] = FIND_REQUESTS_PENDING;
	            	    task.execute(params);
					}else{
						//an error occcured
						Log.e(Constants.LOG_TAG,"ERROR: hasAppFriends = NULL");
					}
				}else{
					//TODO 
				}
			}
		});
		
		return view;
	}
	
	private void getFBFriends(){
	    Session activeSession = Session.getActiveSession();
	    if(activeSession.getState().isOpened()){
	        Request friendRequest = Request.newMyFriendsRequest(activeSession, 
	            new GraphUserListCallback(){
	                @Override
	                public void onCompleted(List<GraphUser> users,
	                        Response response) {
	                    allMyFBFriends = users;
	                    taskOb.increment();
	                }
	        });
	        Bundle params = new Bundle();
	        params.putString("fields", "id, name, picture");
	        friendRequest.setParameters(params);
	        friendRequest.executeAsync();
	    }
	}
	
	private void onSessionStateChange(final Session session, SessionState state, Exception exception) {
	    if (session != null && session.isOpened()) {
	        // Get the user's data.
	        makeMeRequest(session);
	    }
	}
	
	private void getFriendsToInvite(){
		
		if (allMyFBFriends != null){
			for (GraphUser graphUser : allMyFBFriends){
				if (!(myAcceptedFriendsStr.contains(graphUser.getId()) || myPendingFriendsStr.contains(graphUser.getId()))){
					myFriendsCouldInvite.add(graphUser);
				}
			}
		}
	}
	
	private void makeMeRequest(final Session session) {
	    // Make an API call to get user data and define a 
	    // new callback to handle the response.
	    Request request = Request.newMeRequest(session, 
	            new Request.GraphUserCallback() {
	        @Override
	        public void onCompleted(GraphUser user, Response response) {
	            // If the response is successful
	            if (session == Session.getActiveSession()) {
	                if (user != null) {
	                    // Set the id for the ProfilePictureView
	                    // view that in turn displays the profile picture.
	                    profilePictureView.setProfileId(user.getId());
	                    // Set the Textview's text to the user's name.
	                    userNameView.setText(user.getName());
	                    currentUserId = user.getId();
	                    Log.w(Constants.LOG_TAG,"currentUserId ===> " + currentUserId);
	            	    GetFriendsTask task = new GetFriendsTask();
	            	    String[] params = new String[2];
	            	    params[0] = user.getId();
	            	    params[1] = FIND_REQUESTS_ACCEPTED;
	            	    task.execute(params);
	                }
	            }
	            if (response.getError() != null) {
	                // Handle errors, will do so later.
	            }
	        }
	    });
	    request.executeAsync();
	}
	
	private class GetFriendsTask extends AsyncTask<String, Void, List<ParseObject>> {

	    @Override
		protected void onPreExecute() {
			super.onPreExecute();
			loading.setVisibility(View.VISIBLE);
		}
		
		@Override
	    protected List<ParseObject> doInBackground(String... params) {

	    	if (params != null){
	    		
	    		final String userId = params[0];
	    		final String option = params[1];
	    		
	    		ParseQuery<ParseObject> queryPart1 = ParseQuery.getQuery(FriendRequestDBHelper.PARSE_DB_TABLENAME_FRIENDREQUESTS);
	    		queryPart1.whereEqualTo(FriendRequestDBHelper.PARSE_DB_FIELD_SENDERID, userId);
	    		
	    		ParseQuery<ParseObject> queryPart2 = ParseQuery.getQuery(FriendRequestDBHelper.PARSE_DB_TABLENAME_FRIENDREQUESTS);
	    		queryPart2.whereEqualTo(FriendRequestDBHelper.PARSE_DB_FIELD_RECEIVERID, userId);
	    		
	    		if(option.equals(FIND_REQUESTS_ACCEPTED)){
	    			queryPart1.whereEqualTo(FriendRequestDBHelper.PARSE_DB_FIELD_ACCEPTED, FriendRequestConstants.FRIEND_REQUEST_ACCEPTED);
	    			queryPart2.whereEqualTo(FriendRequestDBHelper.PARSE_DB_FIELD_ACCEPTED, FriendRequestConstants.FRIEND_REQUEST_ACCEPTED);
	    		}else if (option.equals(FIND_REQUESTS_PENDING)){
	    			queryPart1.whereEqualTo(FriendRequestDBHelper.PARSE_DB_FIELD_ACCEPTED, FriendRequestConstants.FRIEND_REQUEST_PENDING);
	    			queryPart2.whereEqualTo(FriendRequestDBHelper.PARSE_DB_FIELD_ACCEPTED, FriendRequestConstants.FRIEND_REQUEST_PENDING);
	    		}
	    		
	    		List<ParseQuery<ParseObject>> fullQuery = new ArrayList<ParseQuery<ParseObject>>();
	    		fullQuery.add(queryPart1);
	    		fullQuery.add(queryPart2);
	    		
	    		ParseQuery.or(fullQuery).findInBackground(new FindCallback<ParseObject>() {
					@Override
					public void done(List<ParseObject> myFriendsPO, ParseException e) {
	    		        if (e == null) {
	    		        	
	    		        	if(myFriendsPO.size() > 0){
	    		        		for (ParseObject friend : myFriendsPO)
	    		        		{
	    		    	    		if(option.equals(FIND_REQUESTS_ACCEPTED)){
	    		    	    			myAcceptedFriends.add(friend);
	    		    	    			if(friend.getString(FriendRequestDBHelper.PARSE_DB_FIELD_RECEIVERID).equals(currentUserId)){
	    		    	    				myAcceptedFriendsStr.add(friend.getString(FriendRequestDBHelper.PARSE_DB_FIELD_SENDERID));
	    		    	    			}else{
	    		    	    				myAcceptedFriendsStr.add(friend.getString(FriendRequestDBHelper.PARSE_DB_FIELD_RECEIVERID));
	    		    	    			}
	    		    	    			
	    		    	    		}else if (option.equals(FIND_REQUESTS_PENDING)){
	    		    	    			myPendingFriends.add(friend);    	
	    		    	    			if(friend.getString(FriendRequestDBHelper.PARSE_DB_FIELD_RECEIVERID).equals(currentUserId)){
	    		    	    				myPendingFriendsStr.add(friend.getString(FriendRequestDBHelper.PARSE_DB_FIELD_SENDERID));
	    		    	    			}else{
	    		    	    				myPendingFriendsStr.add(friend.getString(FriendRequestDBHelper.PARSE_DB_FIELD_RECEIVERID));
	    		    	    			}
	    		    	    		}
	    		        			
	    		        		}
	    		        		if(option.equals(FIND_REQUESTS_ACCEPTED)){
	    		        			Log.d(Constants.LOG_TAG, "we successfully retrieved from Cloud the friends of this user [" + userId + "]. This user has " + myAcceptedFriends.size() + " friends.");
    		    	    			
    		    	    		}else if (option.equals(FIND_REQUESTS_PENDING)){
    		    	    			Log.d(Constants.LOG_TAG, "we successfully retrieved from Cloud the friends of this user [" + userId + "]. This user has " + myPendingFriendsStr.size() + " pending friends.");
    		    	    		}
	    		        		
	    		        		adapter.notifyDataSetChanged();
	    		        		loading.setVisibility(View.GONE);
	    		        		hasAppFriends = true;
	    		        		
	    		        		if(option.equals(FIND_REQUESTS_PENDING)){
	    		        			taskOb.increment();
	    		        		}
	    		        	}else{
	    		        		if(option.equals(FIND_REQUESTS_PENDING)){
	    		        			Log.d(Constants.LOG_TAG, "This user [" + userId + "] has no pending friend request");
	    		        			taskOb.increment();
	    		        		}else{
	    		        			Log.d(Constants.LOG_TAG, "This user [" + userId + "] has no friend");
		    		        		loading.setVisibility(View.GONE);
		    		        		noFriendTView.setVisibility(View.VISIBLE);
		    		        		hasAppFriends = false;
	    		        		}
	    		        	}
	    		        } else {
	    		        	Log.w(Constants.LOG_TAG, "we coudln't retrieve from Cloud the friends of this user [" + userId + "].");
	    		        }
						
					}
	    		});
	    		
	    		return myAcceptedFriends;
	    	}
	    	return null;
	    }
	}
	
	private class MyFriendsAdapter extends ArrayAdapter<ParseObject>{

		List<ParseObject> _myFriends;
		
		public MyFriendsAdapter(Context context, int resource,
				List<ParseObject> objects) {
			super(context, resource, objects);
			
			_myFriends = objects;
		}
		
		@Override
	    public View getView(final int position, View convertView, ViewGroup parent) {
			
	        View view = convertView;
	        if (view == null) {
	        	LayoutInflater inflater = (LayoutInflater)getContext().getSystemService
	        		      (Context.LAYOUT_INFLATER_SERVICE);
	            view = inflater.inflate(R.layout.row_my_friend, parent,false);
	        }

	        ParseObject friendRequestPO = _myFriends.get(position);
	        
            TextView nameTextV = (TextView) view.findViewById(R.id.friendrequest_name);
            ProfilePictureView profilePictureView = (ProfilePictureView)view.findViewById(R.id.friendrequest_picture);
            
            String friendId = friendRequestPO.getString(FriendRequestDBHelper.PARSE_DB_FIELD_RECEIVERID);
            if(friendId.equals(currentUserId)){
            	friendId = friendRequestPO.getString(FriendRequestDBHelper.PARSE_DB_FIELD_SENDERID);
            }
            
            Log.d(Constants.LOG_TAG,"friendId == " + friendId);
            Log.d(Constants.LOG_TAG,"currentUserId == " + currentUserId);
            
            profilePictureView.setProfileId(friendId);
            
            nameTextV.setText("fake name");
	        
	        return view;
	    }
	}
	
	private class MyFriendsToInviteAdapter extends ArrayAdapter<GraphUser>{

		List<GraphUser> _myFriends;
		
		public MyFriendsToInviteAdapter(Context context, int resource,
				List<GraphUser> objects) {
			super(context, resource, objects);
			
			_myFriends = objects;
		}
		
		@Override
	    public View getView(final int position, View convertView, ViewGroup parent) {
			
	        View view = convertView;
	        if (view == null) {
	        	LayoutInflater inflater = (LayoutInflater)getContext().getSystemService
	        		      (Context.LAYOUT_INFLATER_SERVICE);
	            view = inflater.inflate(R.layout.row_invite_friends, parent,false);
	        }

	        final GraphUser graphUser = _myFriends.get(position);
	        
            TextView nameTextV = (TextView) view.findViewById(R.id.friendtoinvite_name);
            ProfilePictureView profilePictureView = (ProfilePictureView)view.findViewById(R.id.friendtoinvite_picture);
            final TextView inviteSentTV = (TextView) view.findViewById(R.id.invite_sent);
            final Button button = (Button) view.findViewById(R.id.btn_invite);
            
            profilePictureView.setProfileId(graphUser.getId());
            nameTextV.setText(graphUser.getName());
            
            button.setOnClickListener(new OnClickListener() {
				@Override
				public void onClick(View v) {
					InviteFriendTask task = new InviteFriendTask();
					String[] params = new String[2];
					params[0] = currentUserId;
					params[1] = graphUser.getId();
					task.execute(params);
					button.setVisibility(View.GONE);
					inviteSentTV.setVisibility(View.VISIBLE);
				}
			});
	        
	        return view;
	    }
	}
	
	private class InviteFriendTask extends AsyncTask<String, Void, Void> {

		@Override
	    protected Void doInBackground(String... userIds) {

	    	if (userIds != null){
	    		final String userId = userIds[0];
	    		final String friendId = userIds[1];
	    		
	    		if (userId != null && friendId != null){
	    			ParseObject friendRequestParseObject = new ParseObject (FriendRequestDBHelper.PARSE_DB_TABLENAME_FRIENDREQUESTS);
	    			
	    			friendRequestParseObject.put(FriendRequestDBHelper.PARSE_DB_FIELD_SENDERID, userId);
	    			friendRequestParseObject.put(FriendRequestDBHelper.PARSE_DB_FIELD_RECEIVERID, friendId);
	    			friendRequestParseObject.put(FriendRequestDBHelper.PARSE_DB_FIELD_ACCEPTED, FriendRequestConstants.FRIEND_REQUEST_PENDING);

	    			friendRequestParseObject.saveInBackground(new SaveCallback() {
	    				
	    				@Override
	    				public void done(ParseException e) {
	    					if (e == null){
	    						Log.d(Constants.LOG_TAG, "we successfully updated to Cloud the friendRequest between [" + userId + "] and ["+ friendId + "]");
	    					}else{
	    						Log.w(Constants.LOG_TAG, "PROBLEM when trying to update friendRequest between [" + userId + "] and ["+ friendId + "] errorMessage:: " + e);
	    						//TODO manage the unicity in Cloud Code so you can't enter twice a FR
	    					}
	    					
	    				}
	    			});
	    		}else if (userId == null){
	    			Log.e(Constants.LOG_TAG,"ERROR :: InviteFriendToTrainingTask :: doInBackground :: userId is NULL");
	    		}else{
	    			Log.e(Constants.LOG_TAG,"ERROR :: InviteFriendToTrainingTask :: doInBackground :: trainingId is NULL");
	    		}
	    		
	    	}
	    	return null;
	    }
	}
	
	private class TaskResultObservable extends Observable{
		private int count;
		
		TaskResultObservable(){
			this.count = 0;
		}
		public void increment() {
			count++;
			setChanged();
		    notifyObservers();
		}
	}
	private class ResultObserver implements Observer
	{
	
	   private TaskResultObservable ov = null;
	   public ResultObserver(TaskResultObservable ov)
	   {
	      this.ov = ov;
	   }
	   public void update(Observable obs, Object obj)
	   {
	      if (obs == ov)
	      {
	         if (ov.count > 1){
	        	 getFriendsToInvite();
	        	 loading.setVisibility(View.GONE);
	        	 adapter2.notifyDataSetChanged();
	         }
	      }
	   }
	}
}
